// Tonality.h: interface for the Tonality class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(_Tonality_H_)
#define _Tonality_H_

#include <math.h>
#include "rsrfft.h"

#define	PI				3.1415926535F
#define TGT_SAMPLERATE	10000	//Hz
#define FFT_ORDER		10
#define FFT_SIZE		(2<<FFT_ORDER) //1024
#define HALF_FFT		(FFT_SIZE/2)
#define FRAME_TIME		80 //ms
#define	SHIFT_TIME		40 //ms
#define FRAME_SIZE		(int)(FRAME_TIME / 1000.0F * TGT_SAMPLERATE)
#define ChromaDim		36
#define	HPCPDim			12
#define FRAME_SHIFT		(int)(SHIFT_TIME/ 1000.0F * TGT_SAMPLERATE)
#define MinF0			110  //Hz  1th octave
#define MaxF0			1000 //Hz	3th octave
#define PeakCover		10	 //Hz, range for select peaks
#define MaxHarmFreq		5000
#define MaxHarmNum		15
#define	hFactor			0.6F	// harmonic effect factor
#define EnvelopRange	200 //Hz
#define	BinCover		4	//bin, chroma weight range
#define	SM_R			2	//frame, bin smooth range
#define	SM_L			(SM_R*2+1)
#define BN				32	// band number, for detect sound part
#define	QSpan			100 //ms, expand time, for detect sound part
#define QThres			7	// quotient threshold for detect sound

struct ChrmWt
{
	float	f;
	float	wt[BinCover];
	int		chrIdx[BinCover];
};

struct ToneInfo
{
	float	major;	// major tonality
	float	minor;	// minor tonality
	float	THPCP[HPCPDim];	// transposed chroma
	int		shift;	// transposition semitone number
};

class Tonality  
{
public:
	Tonality();
	virtual ~Tonality();

	bool	GetAudioHPCP(char *wavFile, float **pHPCP, int *numFeat);
	bool	GetAudioTonality(char *wavFile, ToneInfo *toneInfo);

private:

	SplitRadixFFT *_fftTool;
	float	_hamWin[FFT_SIZE];
	int		_chlMap[HALF_FFT];
	float	_chlWeight[HALF_FFT];
	float	_keyProf[2][12];
	float	*_f0s;
	int		_numF0;
	float	_fStep;
	float	_bandW;
	ChrmWt	*_f0Wt;
	bool	*_bUtter;

	void	GenHamWindow(int frameSize);
	float*	GetFreqPoints(int *numF);
	short*	GetWavData(char *wavFile, int *numData);
	float*	GetFFTPower(short *waveData, int numSamples, int *numFrame);
	short*	DownSampling(short *waveData, int oriSampleRate, int numSample, int *numNewData);
	char*	SelectSpectralPeaks(float *fftPowers, int nFrame);
	float*	CalcSumHarmonics(float *fftPowers, char *bPeak, int nFrame);
	void	GetSpectralEnvelop(float *fft, int num, float *envelop);
	void	WhitenSpectrumWithEnvelop(float *fftPower, int nFrame);
	float*	SumChromaBins(float *sumHarm, int nFrame);
	void	SmoothChroma(float *chroma, int nFrame);
	void	SortQueue(float *queue, int num);
	void	NormalizeChroma(float *chroma, int nFrame);
	void	TuneFrequency(float *chroma, int nFrame);
	float*	Merge3Bin2HPCP(float *chroma, int nFrame);
	float	Mel(int k, float fres) { return (float)(1127.0*log(1.0+k*fres)); }
	void	InitFBank(float lowPass,float highPass);
	bool*	DetectAudioHarmonicPart(float *fftPower, int nFrame);
	void	AdaptPolyProfile();
};

#endif // !defined(_HPCP_H_)
